JS30 Day 8 筆記


Posted by GL on 2023-05-23

功能

1.用 HTML5 canva 做一個畫布
2.滑鼠可畫出不同顏色與粗細的線

Demo

step 1 : 建立 <canvas> 區塊

HTML

// 像素是 800 x 800 的畫布
<canvas id="draw" width="800" height="800"></canvas>

Javascript

const canvas = document.querySelector('#draw') 

// 取得 canvas 的 context,獲得一個 2d 的畫布
const ctx = canvas.getContext('2d')

// canvas 畫布的寬高,設為同視窗大小
canvas.width = window.innerWidth
canvas.height = window.innerHeight

step 2 : 設置各個變數

// 線條的顏色
ctx.strokeStyle = '#BADA55'
// 線條轉角的樣式
ctx.lineJoin = 'round'

// 線條的末端的樣式
ctx.lineCap = 'round'

// 線條的寬度
ctx.lineWidth = 100

// 圖片相疊加時的效果
// ctx.globalCompositeOperation = 'multiply'

// 建立一個變數 idDrawing,判斷是否正在畫圖
let isDrawing = false

// 畫筆起始位置,先預設為 0
let lastX = 0 
let lastY = 0

// hsl 中的色相數值,預設為 0
let hue = 0

// 建立一個變數 direction,判斷是否正在畫圖
let direction = true

step 3 : 建立函式 draw(),執行畫圖

function draw(e){
  // 如果不是 mousedown的事件,isDrawing 為 false 並 return,否則進行下面的程式
  if(!isDrawing) return

  // 設定線條的顏色(HSL 模式)
  ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`

  // 開始規劃畫圖路徑
  ctx.beginPath()

  // 設定畫筆的初始位置
  ctx.moveTo(lastX, lastY)

  // 設定畫到往哪裡
  ctx.lineTo(e.offsetX, e.offsetY);

  //結束規劃路徑
  ctx.closePath();
  // 畫出來 
  ctx.stroke();

  // 用 ES6 賦值的方法,將結束的位置更新為下一次的起始位置
  [lastX, lastY] = [e.offsetX, e.offsetY];

  // 顏色的 HSL 數值加一
  hue++

  // 為了讓顏色不斷地在 HSL 環中循環變化
  // 如果 HSL 數值大於 360, HSL 數值歸零
  if(hue >= 360){
    hue = 0
  }


  // 為了讓線條粗細不斷地在變化,做了二次判斷
  // 如果線條寬度大於或小於某數值,切換 direction
  if(ctx.lineWidth >=100 || ctx.lineWidth <= 1){
    direction = !direction
  }

  // direction 為 true, 線條粗細 + 1,反之 - 1
  if(direction){
    ctx.lineWidth++
  }else{
    ctx.lineWidth--
  }
}

step 4 : 監聽滑鼠操作的事件

// 按下滑鼠時
canvas.addEventListener('mousedown',(e)=>{
  // console.log('mousedown', e)

 // isDrawing 設為 true
 isDrawing = true

 // 將當前滑鼠的位置設為畫筆的起始位置
 [lastX, lastY] = [e.offsetX, e.offsetY]
})

// 當滑鼠移動時,執行 draw()
canvas.addEventListener('mousemove',draw)

// 當滑鼠放開時,isDrawing 設為 false
canvas.addEventListener('mouseup', ()=> isDrawing = false)

// 當滑鼠離開時,isDrawing 設為 false
canvas.addEventListener('mouseout', ()=> isDrawing = false)

 // mouseleave 可以用在結構是多層 div 時的滑鼠離開
  /*canvas.addEventListener('mouseleave', (e) => {
    // console.log('mouseleave', e);
    isDrawing = false;
  });*/

其他補充

  1. 如果要還原上一步的筆劃
    思路:可以把每一步儲存成圖片,然後抽掉步驟的圖片
    getImageData()

  2. 如果出去畫布範圍再回來

// 建立一個變數 idDrawing,判斷是否正在畫圖
let isDrawing = false

// 加這個判斷:建立一個變數 down,判斷是否正按下滑鼠
let down = false

// 按下滑鼠時
canvas.addEventListener('mousedown',(e)=>{
  // console.log('mousedown', e)

  // down 設為 true
  down = true

  // 將當前滑鼠的位置設為畫筆的起始位置
  [lastX, lastY] = [e.offsetX, e.offsetY]
})

// 當滑鼠移動時
canvas.addEventListener('mousemove',()=>{
  // 如果滑鼠沒有按下或沒有畫圖,return,否則執行 draw()
  if(!down ||!drawing) return 
  draw()
})

// 當在視窗內偵測到滑鼠放開時,isDrawing 設為 false
document.addEventListener('mouseup', ()=> isDrawing = false)

// 當滑鼠進入畫布時,isDrawing 設為 false
canvas.addEventListener('mouseleave', ()=>{
  isDrawing = true

  // 將當前滑鼠的位置設為畫筆的起始位置
  [lastX, lastY] = [e.offsetX, e.offsetY]   
})

參考資料:


#JS 30







Related Posts

1789. Primary Department for Each Employee

1789. Primary Department for Each Employee

重新認識Vue.js

重新認識Vue.js

位元運算與邏輯運算與電池燈泡的串聯並聯

位元運算與邏輯運算與電池燈泡的串聯並聯


Comments